function v = RKTreeApply( RKTree, u, N, nLevelCur, nSample )

v = zeros( N, N, nSample );

for iLevel = 1 : nLevelCur - 1

  nWidth = RKTree{iLevel}.nWidth;
  for iRKBlock = 1 : RKTree{iLevel}.nRKBlock
    Source = RKTree{iLevel}.RKSource(:,:,iRKBlock);
    Target = RKTree{iLevel}.RKTarget(:,:,iRKBlock);
    upart = reshape( u( Source(1,1):Source(1,2), ...
      Source(2,1):Source(2,2), : ), nWidth * nWidth, nSample );

    v(Target(1,1):Target(1,2), Target(2,1):Target(2,2), :) = ...
      v(Target(1,1):Target(1,2), Target(2,1):Target(2,2), :) +  ...
      reshape( RKTree{iLevel}.RKBlockU{iRKBlock} * ...
      ( (RKTree{iLevel}.RKBlockV{iRKBlock})' * upart ), ...
      nWidth, nWidth, nSample );

    % Symmetrize
    upart = reshape( u( Target(1,1):Target(1,2), ...
      Target(2,1):Target(2,2), : ), nWidth * nWidth, nSample );
    
    v(Source(1,1):Source(1,2), Source(2,1):Source(2,2), :) = ...
      v(Source(1,1):Source(1,2), Source(2,1):Source(2,2), :) +  ...
      reshape( conj(RKTree{iLevel}.RKBlockV{iRKBlock}) * ...
      ( transpose(RKTree{iLevel}.RKBlockU{iRKBlock}) * upart ), ...
      nWidth, nWidth, nSample );

  end 
end
